package com.baomidou.plugin.idea.mybatisx.advance.processor.clazz;

import com.baomidou.plugin.idea.mybatisx.advance.problem.ProblemBuilder;
import com.baomidou.plugin.idea.mybatisx.advance.util.PsiAnnotationUtil;
import com.baomidou.plugin.idea.mybatisx.advance.util.PsiClassUtil;
import com.baomidou.plugin.idea.mybatisx.advance.util.PsiMethodUtil;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import org.jetbrains.annotations.NotNull;

import java.util.Collection;
import java.util.List;


/**
 * mybatis plus 生成方法基类
 * 本类部分代码来自于lombok idea plugin
 * @author wanglei
 */
public abstract class AbstractMPOnceMethodGenClassProcessor extends AbstractMPClassProcessor implements MPClassProcessor {

    protected AbstractMPOnceMethodGenClassProcessor(@NotNull String supportedAnnotation, @NotNull Class supportedClass) {
        super(supportedAnnotation, supportedClass);
    }
    @Override
    protected boolean validate(@NotNull PsiAnnotation psiAnnotation, @NotNull PsiClass psiClass, @NotNull ProblemBuilder builder) {
        final boolean result = validateAnnotationOnRigthType(psiClass, builder);
        if (result) {
            validateExistingMethods(psiClass, builder);
        }

        final Collection<String> excludeProperty = PsiAnnotationUtil.getAnnotationValues(psiAnnotation, "exclude", String.class);
        final Collection<String> ofProperty = PsiAnnotationUtil.getAnnotationValues(psiAnnotation, "of", String.class);

        if (!excludeProperty.isEmpty() && !ofProperty.isEmpty()) {
            builder.addWarning("exclude and of are mutually exclusive; the 'exclude' parameter will be ignored");//TODO add QuickFix  : remove all exclude params
        } else {
            validateExcludeParam(psiClass, builder, excludeProperty);
        }
        validateOfParam(psiClass, builder, ofProperty);
        validateCallSuperParam(psiAnnotation, psiClass, builder, getMethodName() + "()");
        return result;
    }


    protected boolean validateAnnotationOnRigthType(@NotNull PsiClass psiClass, @NotNull ProblemBuilder builder) {
        boolean result = true;
        if (psiClass.isAnnotationType() || psiClass.isInterface()) {
            builder.addError("@Wrapperable is only supported on a class or enum type");
            result = false;
        }
        return result;
    }

    protected boolean validateExistingMethods(@NotNull PsiClass psiClass, @NotNull ProblemBuilder builder) {
        boolean result = true;

        final PsiMethod[] classMethods = PsiClassUtil.collectClassMethodsIntern(psiClass);
        if (PsiMethodUtil.hasMethodByName(classMethods, getMethodName())) {
            builder.addWarning(String.format("Not generated '%s'(): A method with same name already exists", getMethodName()));
            result = false;
        }

        return result;
    }

    protected <Psi extends PsiElement> void processIntern(@NotNull PsiClass psiClass, @NotNull PsiAnnotation psiAnnotation, @NotNull List<Psi> target) {
        target.addAll((Collection<? extends Psi>) createToStringMethod(psiClass, psiAnnotation));
    }

    abstract String getMethodName();

    @NotNull
    abstract Collection<PsiMethod> createToStringMethod(@NotNull PsiClass psiClass, @NotNull PsiElement psiNavTargetElement);

}
